#include "linkfabric/Message.hpp"
#include <cstring>

using namespace linkfabric;

std::vector<uint8_t> Message::encode() const {
    std::vector<uint8_t> out;
    out.reserve(8 + body.size() * 4); 
    out.push_back(header.version);
    out.push_back(header.msg_type);
    out.push_back(header.flags);
    // total_length will be filled by caller if needed
    out.push_back(static_cast<uint8_t>(header.total_length >> 24));
    out.push_back(static_cast<uint8_t>(header.total_length >> 16));
    out.push_back(static_cast<uint8_t>(header.total_length >> 8));
    out.push_back(static_cast<uint8_t>(header.total_length & 0xFF));
    out.push_back(static_cast<uint8_t>(header.channel_id >> 8));
    out.push_back(static_cast<uint8_t>(header.channel_id & 0xFF));
    for (auto& tlv : body) {
        auto chunk = tlv.encode();
        out.insert(out.end(), chunk.begin(), chunk.end());
    }
    return out;
}

Message Message::decode(const std::vector<uint8_t>& raw) {
    Message msg;
    size_t off = 0;
    msg.header.version     = raw[off++];
    msg.header.msg_type    = raw[off++];
    msg.header.flags       = raw[off++];
    msg.header.total_length = (static_cast<uint32_t>(raw[off++]) << 24) |
                              (static_cast<uint32_t>(raw[off++]) << 16) |
                              (static_cast<uint32_t>(raw[off++]) << 8)  |
                              static_cast<uint32_t>(raw[off++]);
    msg.header.channel_id  = (static_cast<uint16_t>(raw[off++]) << 8) |
                              static_cast<uint16_t>(raw[off++]);
    while (off < raw.size()) {
        msg.body.push_back(TLV::decode(raw, off));
    }
    return msg;
}